﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Duellum.Core;
using JpLabs.Geometry;
using JpLabs.Extensions;

namespace Duellum.Game
{
	/// <summary>
	/// An IDuelCommand is provided by the game machine to the interfaces
	/// It is associated directly to the current player or one of his belongings
	/// </summary>
	/// <remarks>
	/// Known possible commands:
	///		- Move (position)
	///		- Turn (direction)
	///		- ChangeStance
	///		- EndTurn
	///		- Pick, Drop, Throw
	///		- Fire, Reload
	///		- Use, TurnOn, TurnOff, Eat, Arm, Disarm, Dress, Undress
	///		- Compose, Decompose
	/// 
	/// A command can require parameters like these:
	///		- Direction, Position
	///		- Intensity, Timeout
	///		- BodyPlace
	///		- Stance
	///		- Object (on Map, on Player, on Player's backpack, on other player's)
	///		- OtherPlayer (from Map, from custom list(known players, friendly monsters, etc.))
	///		- OtherPlayer's Limb
	///	
	/// A command may have output data like these:
	///		- Time units to execute
	///		- Estimated chance of success
	///	
	/// A command may be broken in several sub-commands (or Actions):
	/// - Turn (one notch);
	/// - Move (one step);
	/// - Hold (for one time unit);
	///	
	///	Parameters may require custom interfaces for being chosen by the actual player.
	///	TODO: How to simulate the execution of a command?
	/// </remarks>
	public interface IDuelCommand
	{
		DuelTypeId Id { get; }
		
		//event EventHandler CanExecuteChanged; //in order for this to work, command objects had to be kept by the game machine

		bool CanExecute(IEnumerable<object> values);
		
		//TODO: Should the command really be executed or should it return the 
		IDuelActionSequence Execute(IEnumerable<object> values);
		
		//IEnumerable<IDuelCommandParam> GetExpectedParamTypes();
	}
	
	public interface IDuelActionSequence
	{}

	public static class DuelCommandExt
	{
		static public bool CanExecute<T>(this IDuelCommand cmd, T value)
		{
			return cmd.CanExecute(value.ToEnumerable<object>());
		}

		static public IDuelActionSequence Execute<T>(this IDuelCommand cmd, T value)
		{
			return cmd.Execute(value.ToEnumerable<object>());
		}
	}

	public interface IDuelCommandParam
	{
		//DuelTypeId Id { get; }
		Type Type { get; }
		bool IsCoercible(object value);
	}
	
	public static class DuelCoreCommands
	{
		public const string Turn = "BaseCmds.Turn";
		public const string Move = "BaseCmds.Move";
		
		//public const string AngleParam = "BaseCmds.Turn.Angle";
	}
}
